package com.polaris.live.ui.live.activity

import android.content.Intent
import android.os.Bundle
import android.view.MotionEvent
import android.view.WindowManager
import androidx.core.os.bundleOf
import androidx.lifecycle.viewModelScope
import com.blankj.utilcode.util.StringUtils
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.manager.CoroutineScopeManager
import com.polaris.live.common.network.parseState
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.LiveConst
import com.polaris.live.databinding.ActivityLiveSpectatorBinding
import com.polaris.live.im.sfs.bean.live.ext.UserBasicVo
import com.polaris.live.manager.LiveStateManager
import com.polaris.live.popup.GameListPopup
import com.polaris.live.resp.event.WebSpectatorEvent
import com.polaris.live.translation.R.string
import com.polaris.live.ui.game.GameUtils
import com.polaris.live.ui.live.activity.base.BaseLiveActivity
import com.polaris.live.ui.live.bean.LiveSpectatorBean
import com.polaris.live.ui.live.fragment.LiveSpectatorFragment
import com.polaris.live.utils.XActivityUtils
import com.polaris.live.utils.fragment.attachFragment
import com.polaris.live.utils.getBooleanOrString
import com.polaris.live.utils.getLongOrString
import com.polaris.live.utils.route.RoutePath
import com.polaris.live.utils.route.Router
import com.polaris.live.utils.route.RouterUtils
import com.polaris.live.utils.zego.LiveActivityIdentifier
import com.polaris.live.utils.zego.LivePlayer
import com.polaris.live.utils.zego.LivePlayerLifecycle
import com.polaris.live.utils.zego.listener.OnLivePlayListener
import com.polaris.live.viewmodel.live.LiveVideoViewModel
import im.zego.zegoexpress.constants.ZegoPlayerState
import im.zego.zegoexpress.constants.ZegoRemoteDeviceState
import im.zego.zegoexpress.entity.ZegoPlayStreamQuality
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.json.JSONObject

/**
 * SpectatorActivity  观众端
 *
 * @author Created by 半仙 on 2023/9/27/027 17:19
 */
class LiveSpectatorActivity : BaseLiveActivity<LiveVideoViewModel, ActivityLiveSpectatorBinding>() {

    private lateinit var mLiveData: LiveSpectatorBean //直播数据

    private var mAnchorId: Long = -1

    private var mCurrentStreamId: String? = null

    private var mLiveExiting: Boolean = false

    private var mIsShowFirstFrame = false //是否显示过第一帧

    private var mLowerBroadcast = false //是否已经下拨

    private val mLivePlayListener = object : OnLivePlayListener {
        override fun onPlayStart() {
            mIsShowFirstFrame = false
        }

        override fun onPlayStop() {
            mIsShowFirstFrame = false
            waitFirstFrame?.cancel()
            waitFirstFrame = null
        }

        override fun onPlayerRenderVideoFirstFrame() {
            mIsShowFirstFrame = true
            showLiveUi()
        }

        override fun onPlayerStateUpdate(
            state: ZegoPlayerState?,
            errorCode: Int,
            extendedData: JSONObject?,
        ) {
            if (state == ZegoPlayerState.NO_PLAY && errorCode != 0) { //拉流失败
                stopLiveUi()
            }
        }

        override fun onRemoteSpeakerStateUpdate(state: ZegoRemoteDeviceState) {
            if (state == ZegoRemoteDeviceState.OPEN) {
                showLiveUi()
            } else {
                if (state == ZegoRemoteDeviceState.NOT_SUPPORT) {
                    mViewModel.detectRoom(mAnchorId)
                }
                stopLiveUi()
            }
        }

        override fun onPlayerQualityUpdate(quality: ZegoPlayStreamQuality) {
            mFragment.onPlayerState(quality)
        }
    }

    private var waitFirstFrame: Job? = null //等待第一帧
    private fun showLiveUi() {
        //获取过第一帧说明是重连可以直接执行
        if (mIsShowFirstFrame) {

            waitFirstFrame?.cancel()
            waitFirstFrame = null
            if (LivePlayer.playingStreamId(mCurrentStreamId)) {
                mFragment.playSuccessful()
                mFragment.anchorEnterLive()
            }

        } else {
            waitFirstFrame = mViewModel.viewModelScope.launch {
                try {
                    delay(200) //200毫秒第一帧没过来显示轮播图
                    stopLiveUi()
                } finally {
                    if (waitFirstFrame == coroutineContext[Job]) {
                        waitFirstFrame = null
                    }
                }
            }
        }
    }

    private fun stopLiveUi() {
        if (!mIsShowFirstFrame) {
            mFragment.anchorLeaveLive()
        }
    }

    private val mLivePlayerLifecycle by lazy {
        LivePlayerLifecycle(
            LiveActivityIdentifier.LIVE_SPECTATOR_ACTIVITY,
            false,
            mBinding.cameraPreview,
            mLivePlayListener,
            mCurrentStreamId
        )
    }

    private val mFragment by lazy {
        supportFragmentManager.attachFragment(com.polaris.live.R.id.fl_fragment) {
            LiveSpectatorFragment().apply {
                arguments = bundleOf("anchorId" to mAnchorId)
            }
        }
    }

    private val mGameListener = object : GameUtils.GameStateListener {
        override fun gameStart() { //游戏打开
        }

        override fun gameClose() { //游戏关闭
            if (mLowerBroadcast) {  //主播下播退出直播间
                finish()
            }
        }
    }

    override fun initImmersionBar() {

    }

    override fun initView(savedInstanceState: Bundle?) {
        super.initView(savedInstanceState)
        XActivityUtils.killOtherRoomActivity(LiveSpectatorActivity::class.java)
        mLiveData = intent.toLiveData()

        if (mLiveData.anchorId <= 0) {
            finish()
            return
        }

        window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)

        mAnchorId = mLiveData.anchorId

        //观众进入直播状态
        LiveStateManager.updateSpectateState(true)

        initListener()

        //初始化直播间
        initLive(mLiveData)

        if (mLiveData.isGame) { //是否需要打开游戏列表
            GameListPopup.show(
                this,
                GameUtils.getLiveCacheGameList() ?: GameUtils.getMeCacheGameList(),
                mLiveData.anchorId.toString()
            )
        }
    }

    private fun initListener() {
        GameUtils.addGameStateListener(mGameListener)

        mLivePlayerLifecycle.observe(this)

        mFragment.setOnScrollViewListener {
            mBinding.cameraPreview.translationY = it.toFloat()
        }
        mFragment.setOnSwitchLiveListener {
            switchLive(it)
        }
        mFragment.setOnCloseListener {
            exitAndFinish()
        }
        //接收到服务端的关闭直播
        mFragment.setOnServerCloseListener {
            if (it != null) {
                /**
                 * 用户和第一个数据相等和游戏在运行时退出直播间否则切换直播间
                 */
                if (mLiveData.anchorId == it.anchorId || GameUtils.gameRun) {
                    if (!GameUtils.gameRun) {
                        if (!LiveStateManager.isCalling()) {
                            Router.builder(RoutePath.LIVE_SPECTATOR_END_ACTIVITY)
                                .withAny("data", it)
                                .withInt("fromType", LiveConst.Type.LIVE_AND_MATCH)
                                .navigation(this)
                        }
                    }
                    onExitLive()
                } else {
                    mBinding.root.post {
                        mFragment.scrollNext()
                    }
                }
            }
        }

        mViewModel.joinLiveLiveData.observe(this) { reusltState ->
            parseState(reusltState, {
                when (it.info.type) {
                    LiveConst.Type.PARTY_GAME_LIVE -> {
                        finish()
                        Router.instance.setPath(RoutePath.PARTY_GAME_SPECTATOR_ACTIVITY)
                            .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                            .withAny(LiveConst.Params.LIVEINITINFO, it)
                            .navigation(this)
                    }

                    LiveConst.Type.PARTY_LIVE, LiveConst.Type.VIDEO_PARTY -> {
                        finish()
                        Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                            .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                            .withInt(LiveConst.Params.LIVETYPE, it.info.type)
                            .withAny(LiveConst.Params.LIVEINITINFO, it)
                            .navigation(this)
                    }

                    else -> {
                        playStream(it.info.streamId)
                        mFragment.initLiveInfo(it)

                        RouterUtils.routerGotoChild(this, mBinding.root)
                    }
                }
            }, {
                if (it.errCode == CommonConst.ErrorCode.PARTY_NEED_PASSWORD) {
                    finish()
                    Router.instance.setPath(RoutePath.PARTY_SPECTATOR_ACTIVITY)
                        .withLong(LiveConst.Params.ANCHORID, mAnchorId)
                        .withInt(LiveConst.Params.LIVETYPE, LiveConst.Type.PARTY_LIVE)
                        .navigation(this)
                    return@parseState
                } else if (it.errCode == CommonConst.ErrorCode.KICK_ROOM) { //KICK_ROOM 被踢出了房间
                    ToastGravity.showGravity(StringUtils.getString(string.kicked_out_room_tips))
                    finish()
                    return@parseState
                } else if (it.errCode == CommonConst.ErrorCode.LIVE_NOT_EXIST){
                    mLivePlayerLifecycle.stopStream()
                }
                mFragment.loadFailure(it.errorMsg)

                mBinding.root.post {
                    mViewModel.viewModelScope.launch {
                        delay(1000)
                        withContext(CoroutineScopeManager.mainDispatcher) {
                            mFragment.scrollNext()
                        }
                    }
                }

            })
        }

        mViewModel.detectRoomLiveData.observe(this) { reusltState ->
            parseState(reusltState, {
            }, {
                if (CommonConst.ErrorCode.LIVE_NOT_EXIST == it.errCode) { //直播间不存在了
                    ToastGravity.showGravity(getString(string.down_streamed))
                }
            })
        }

        mViewModel.exitLiveLiveData.observe(this)
        {
            //不为空说明是切换直播间，开始加入新的直播间
            if (it != null) {
                mViewModel.joinLive(it.anchorId)
            } else {
                onExitLive()
            }
        }
    }

    private fun initLive(bean: LiveSpectatorBean) {
        startLoading(bean, false)
        //开始加入直播间
        mViewModel.joinLive(bean.anchorId)
    }

    private fun switchLive(bean: LiveSpectatorBean) {
        if (bean.anchorId <= 0) {
            return
        }

        //先离开上一个直播间
        mViewModel.exitLive(mAnchorId, bean)

        //先替换部分参数
        mAnchorId = bean.anchorId

        if (!mFragment.isStateSaved) {
            mFragment.arguments = bundleOf("anchorId" to mAnchorId)
        }
        startLoading(bean, true)
    }

    private fun startLoading(bean: LiveSpectatorBean, isSwitchLive: Boolean) {
        var needLoading = true
        //如果有流要判断与当前是否一致
        if (bean.streamId != null) {
            //如果相同则说明不需要遮罩
            if (LivePlayer.playingStreamId(bean.streamId)) {
                needLoading = false
            }
            //流不等于空则直接播放
            playStream(bean.streamId)
        }

        //用户信息不为空也不需要遮罩
        if (bean.userBasic != null) {
            needLoading = false
        }

        if (isSwitchLive) {
            mFragment.switchLoading(needLoading, bean)
        } else {
            mFragment.startLoading(needLoading, bean)
        }

        if (bean.userBasic != null) {
            mFragment.preUserInfo(bean.userBasic)
        }
    }

    private fun playStream(streamId: String) {
        if (mLivePlayerLifecycle.getNowPlayStreamId() != streamId || !mLivePlayerLifecycle.isStreamIdPaly(
                streamId
            )
        ) { //不相等会取消流再播放
            mCurrentStreamId = streamId
//            if(LivePlayer.playingStreamId(mCurrentStreamId)){
//                mLivePlayerLifecycle.stopStream()
//            }
            mLivePlayerLifecycle.switchStream(this, streamId)
        } else { //相等直接播放成功
            showLiveUi()
        }
    }

    private fun exitAndFinish() {
        mLiveExiting = true

        mViewModel.exitLive(mAnchorId)
    }

    override fun onNewIntent(intent: Intent) {
        super.onNewIntent(intent)

        mFragment.onSwitchView(intent.toLiveData())
    }

    override fun onNetwork(isNetwork: Boolean, isConnected: Boolean) {
        mFragment.onNetwork(isNetwork, isConnected)
    }

    private fun onExitLive() {
        if (!GameUtils.gameRun) {
            finish()
        } else {
            mLivePlayerLifecycle.stopStream()
            mFragment.anchorLeaveLive(true)
        }
        mLowerBroadcast = true
    }

    override fun onBackPressed() {
        if (mLiveExiting) {
            return
        }

        exitAndFinish()
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEndSpectatorEvent(event: WebSpectatorEvent) {
        if (event.isNeedClose) {
            exitAndFinish()
        } else {
            mFragment.setOnSwitchRoomListener(event.anchorId, event.childRouter)
        }
    }

    override fun dispatchTouchEvent(ev: MotionEvent): Boolean {
        return mFragment.dispatchTouchEvent(ev) || super.dispatchTouchEvent(ev)
    }

    private fun Intent.toLiveData(): LiveSpectatorBean {
        val anchorId = getLongOrString("anchorId", -1L)
        val coverUrl = getStringExtra("cover")
        val streamId = getStringExtra("streamId")
        val isGame = getBooleanOrString("isGame", false)
        val userBasic = getParcelableExtra<UserBasicVo>("user")

        return LiveSpectatorBean(anchorId, coverUrl, streamId, userBasic, isGame)
    }

    override fun onDestroy() {
        super.onDestroy()
        GameUtils.removeGameStateListener(mGameListener)
        LiveStateManager.updateSpectateState(false)
    }

}